#include <iostream>
#include <string>
#include <list>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::list;
using std::unique_ptr;

class Observer
{
public:
    virtual void update(int status) = 0;
    virtual ~Observer(){}
};

class ConcreteObserverA
: public Observer
{
public:
    ConcreteObserverA(const string &name)
    : _name(name)
    {

    }

    virtual void update(int status) override
    {
        cout << "ConcreteObserverA " << _name << ", " << status << endl;
    }

private:
    string _name;
};

class ConcreteObserverB
: public Observer
{
public:
    ConcreteObserverB(const string &name)
    : _name(name)
    {

    }

    virtual void update(int status) override
    {
        cout << "ConcreteObserverB " << _name << ", " << status << endl;
    }

private:
    string _name;
};

class Subject
{
public:
    //添加观察者
    virtual void attach(Observer *pobserver) = 0;
    //删除观察者
    virtual void detach(Observer *pobserver) = 0;
    //当状态发生变更的时候，给观察者发通知
    virtual void notify() = 0;

    virtual ~Subject() {}
};

class ConcreteSubject
: public Subject
{
public:
    //添加观察者
    virtual void attach(Observer *pobserver)  override
    {
        if(pobserver)
        {
            _obList.push_back(pobserver);
        }
    }

    //删除观察者
    virtual void detach(Observer *pobserver) override
    {
        if(pobserver)
        {
            _obList.remove(pobserver);
        }
    }

    void setStatus(int status)
    {
        _status = status;
    }

    int getStatus()
    {
        return _status;
    }

    //当状态发生变更的时候，给观察者发通知
    virtual void notify() override
    {
        for(auto &elem : _obList)
        {
            elem->update(_status);//多态
        }
    }
private:
    list<Observer *> _obList;//存放所有观察者的容器
    int _status;//主题的状态
};

void test()
{
    //创建出观察者的对象
    unique_ptr<Observer> oba(new ConcreteObserverA("lili"));
    unique_ptr<Observer> obb(new ConcreteObserverB("lucy"));
    //创建具体的主题
    unique_ptr<ConcreteSubject> sub(new ConcreteSubject());

    //将每个观察者添加到主题的数据成员中存起来
    sub->attach(oba.get());
    sub->attach(obb.get());

    //主题的状态发生变更
    sub->setStatus(1);

    //主题的状态发生变更之后，就可以发通知，告诉观察者
    sub->notify();

    cout << endl << endl;
    //如果某个观察者不想关注主题了，就可以执行删除操作
    sub->detach(obb.get());

    //主题的状态发生变更
    sub->setStatus(100);

    //主题的状态发生变更之后，就可以发通知，告诉观察者
    sub->notify();
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

